home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Mac / scripts / cfmfile.py < prev    next >
Encoding:
Python Source  |  2000-06-23  |  5.9 KB  |  237 lines

  1. """cfmfile - Interface to code fragments on file"""
  2. import struct
  3. import Res
  4. import macfs
  5. import string
  6.  
  7. Error = 'cfmfile.Error'
  8.  
  9. READ = 1
  10. WRITE = 2
  11. smAllScripts = -3
  12. BUFSIZE = 0x100000
  13.  
  14. class FragmentInfo:
  15.     """Information on a single fragment"""
  16.     def __init__(self):
  17.         self.arch = 'pwpc'
  18.         self.current_version = 0
  19.         self.oldest_version = 0
  20.         self.stacksize = 0
  21.         self.libdir = 0
  22.         self.fragtype = 1
  23.         self.location = 1
  24.         self.offset = 0
  25.         self.length = 0
  26.         self.res_0 = 0
  27.         self.res_1 = 0
  28.         self.name = ''
  29.         self.ifp = None
  30.         
  31.     def load(self, data):
  32.         if len(data) < 43:
  33.             raise Error, 'Not enough data in cfrg resource'
  34.         self.arch = data[:4]
  35.         self.update, self.current_version, self.oldest_version, \
  36.             self.stacksize, self.libdir, self.fragtype, self.location, \
  37.             self.offset, self.length, self.res_0, self.res_1, length = \
  38.             struct.unpack("llllhbbllllh", data[4:42])
  39.         namelen = ord(data[42])
  40.         self.name = data[43:43+namelen]
  41.         if len(self.name) != namelen:
  42.             raise Error, 'Not enough data in cfrg resource'
  43.         return length
  44.         
  45.     def save(self):
  46.         length = (43+len(self.name)+3) & ~3
  47.         data = self.arch + struct.pack("llllhbbllllh", self.update, \
  48.             self.current_version, self.oldest_version, self.stacksize, \
  49.             self.libdir, self.fragtype, self.location, self.offset, \
  50.             self.length, self.res_0, self.res_1, length)
  51.         data = data + chr(len(self.name)) + self.name
  52.         data = data + ('\0'*(length-len(data)))
  53.         return data
  54.         
  55.     def copydata(self, ofp):
  56.         """Copy fragment data to a new file, updating self.offset"""
  57.         if self.location != 1:
  58.             raise Error, 'Can only copy kOnDiskFlat (data fork) fragments'
  59.         if not self.ifp:
  60.             raise Error, 'No source file for fragment'
  61.         # Find out real length (if zero)
  62.         if self.length == 0:
  63.             self.ifp.seek(0, 2)
  64.             self.length = self.ifp.tell()
  65.         # Position input file and record new offset from output file
  66.         self.ifp.seek(self.offset)
  67.         self.offset = ofp.tell()
  68.         l = self.length
  69.         while l:
  70.             if l > BUFSIZE:
  71.                 ofp.write(self.ifp.read(BUFSIZE))
  72.                 l = l - BUFSIZE
  73.             else:
  74.                 ofp.write(self.ifp.read(l))
  75.                 l = 0
  76.         self.ifp = ofp
  77.         
  78.     def setfile(self, ifp):
  79.         self.ifp = ifp
  80.         
  81. class FragmentResource:
  82.  
  83.     def __init__(self, data):
  84.         self.load(data)
  85.  
  86.     def load(self, data):
  87.         r0, r1, version, r3, r4, r5, r6, nfrag = struct.unpack("llllllll", data[:32])
  88.         if version != 1:
  89.             raise Error, 'Unsupported cfrg version number %d'%version
  90.         data = data[32:]
  91.         self.fragments = []
  92.         for i in range(nfrag):
  93.             f = FragmentInfo()
  94.             len = f.load(data)
  95.             data = data[len:]
  96.             self.fragments.append(f)
  97.         if data:
  98.             raise Error, 'Spurious data after fragment descriptions'
  99.             
  100.     def save(self):
  101.         data = struct.pack("llllllll", 0, 0, 1, 0, 0, 0, 0, len(self.fragments))
  102.         for f in self.fragments:
  103.             data = data+f.save()
  104.         return data
  105.             
  106.     def setfile(self, ifp):
  107.         for f in self.fragments:
  108.             f.setfile(ifp)
  109.             
  110.     def copydata(self, ofp):
  111.         for f in self.fragments:
  112.             f.copydata(ofp)
  113.             
  114.     def getfragments(self):
  115.         return self.fragments
  116.         
  117.     def addfragments(self, fragments):
  118.         self.fragments = self.fragments + fragments
  119.  
  120. class ResourceCollection:
  121.     def __init__(self, fhandle):
  122.         self.reslist = []
  123.         self.fhandle = fhandle
  124.         oldresfile = Res.CurResFile()
  125.         Res.UseResFile(fhandle)
  126.         Res.SetResLoad(0)
  127.         ntypes = Res.Count1Types()
  128.         for itype in range(1, 1+ntypes):
  129.             type = Res.Get1IndType(itype)
  130.             nresources = Res.Count1Resources(type)
  131.             for ires in range(1, 1+nresources):
  132.                 res = Res.Get1IndResource(type, ires)
  133.                 id, type, name = res.GetResInfo()
  134.                 self.reslist.append((type, id))
  135.         Res.SetResLoad(1)
  136.         Res.UseResFile(oldresfile)
  137.             
  138.     def contains(self, type, id):
  139.         return (type, id) in self.reslist
  140.         
  141.     def getresource(self, type, id):
  142.         oldresfile = Res.CurResFile()
  143.         Res.UseResFile(self.fhandle)
  144.         Res.SetResLoad(1)
  145.         resource = Res.Get1Resource(type, id)
  146.         Res.UseResFile(oldresfile)
  147.         return resource
  148.         
  149.     def saveresto(self, type, id, fhandle):
  150.         oldresfile = Res.CurResFile()
  151.         resource = self.getresource(type, id)
  152.         id, type, name = resource.GetResInfo()
  153.         resource.DetachResource()
  154.         Res.UseResFile(fhandle)
  155.         resource.AddResource(type, id, name)
  156.         Res.UseResFile(oldresfile)
  157.         
  158.     def getreslist(self):
  159.         return self.reslist
  160.         
  161. class CfmFile(ResourceCollection, FragmentResource):
  162.     
  163.     def __init__(self, fsspec):
  164.         rfork = Res.FSpOpenResFile(fsspec, READ)
  165.         dfork = open(fsspec.as_pathname(), 'rb')
  166.         ResourceCollection.__init__(self, rfork)
  167.         cfrg_resource = self.getresource('cfrg', 0)
  168.         FragmentResource.__init__(self, cfrg_resource.data)
  169.         self.setfile(dfork)
  170.  
  171. def mergecfmfiles(inputs, output):
  172.     # Convert inputs/outputs to fsspecs
  173.     inputs = map(None, inputs)
  174.     for i in range(len(inputs)):
  175.         if type(inputs[i]) == type(''):
  176.             inputs[i] = macfs.FSSpec(inputs[i])
  177.     if type(output) == type(''):
  178.         output = macfs.FSSpec(output)
  179.         
  180.     input_list = []
  181.     for i in inputs:
  182.         input_list.append(CfmFile(i))
  183.         
  184.     # Create output file, if needed
  185.     creator, tp = inputs[0].GetCreatorType()
  186.     try:
  187.         Res.FSpCreateResFile(output, creator, tp, smAllScripts)
  188.     except Res.Error:
  189.         pass
  190.         
  191.     # Copy fragments
  192.     dfork = open(output.as_pathname(), 'wb')
  193.     for i in input_list:
  194.         i.copydata(dfork)
  195.     dfork.close()
  196.         
  197.     # Merge cfrg's
  198.     for i in input_list[1:]:
  199.         input_list[0].addfragments(i.getfragments())
  200.         
  201.     old_res_file = Res.CurResFile()
  202.     rfork = Res.FSpOpenResFile(output, WRITE)
  203.     Res.UseResFile(rfork)
  204.     
  205.     # Write cfrg
  206.     data = input_list[0].save()
  207.     cfrg_resource = Res.Resource(data)
  208.     cfrg_resource.AddResource('cfrg', 0, '')
  209.     resources_done = [('cfrg', 0)]
  210.     
  211.     # Write other resources
  212.     for i in input_list:
  213.         todo = i.getreslist()
  214.         for tp, id in todo:
  215.             if (tp, id) in resources_done:
  216.                 continue
  217.             i.saveresto(tp, id, rfork)
  218.             resources_done.append(tp, id)
  219.             
  220. def main():
  221.     list = []
  222.     while 1:
  223.         fss, ok = macfs.PromptGetFile("Next input file:", "shlb", "APPL")
  224.         if not ok: break
  225.         list.append(fss)
  226.     if not list:
  227.         sys.exit(0)
  228.     output, ok = macfs.StandardPutFile("Output file:")
  229.     if not ok:
  230.         sys.exit(0)
  231.     mergecfmfiles(list, output)
  232.     
  233. if __name__ == '__main__':
  234.     main()
  235.     
  236.             
  237.